iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 15
1
自我挑戰組

Angular2學習筆記系列 第 15

Angular2 踩雷系列文(一)

  • 分享至 

  • xImage
  •  

情境描述

在Component的ngInit()內,使用Service連接遠端API,

這個遠端API會傳回一顆樹,

這顆樹的畫面被要求要像表格的奇偶列變色

程式測試

假設我先在ngInit(),沒有連結遠端API取樹的值,

而是自己建立的樹狀結構變數treedata

  ngOnInit() {
	this.treedata = [{
	  "name": "A",
	  "submenu": [{
	    "name": "A-1",
		"submenu":[{
		  "name":"A-1-1",
		  "submenu":[]
		}]},{
		"name": "A-2",
		"submenu":[]},
		...
		]},
		...
	]
  }

利用Compoent自己也可當子元件的特性,把這個樹狀結構元件產生出來

in app.component.html

 <tree-table [data]="treedata" [level]="0"><tree-table>

in tree-table.component.thml

<div *ngFor="let item of data">
  <div class="tbrow">
    <div class="tbcell">{{level}}</div>
    <div class="tbcell tbcell-name">
      <span [style.padding-left.px]="level * 10">{{item.name}}</span>
    </div>
    <div class="tbcell">
      <button>Save</button>
    </div>
  </div>
  <tree-table [data]="item.submenu" [level]="level"></tree-table>
</div>

奇偶列的變色,我是使用jQuery的find方法

使用selector.tbrow:even來找到偶數列做變色

而這個jQuery的方法,我是寫在ngAfterViewInit這個生命週期

  ngAfterViewInit() {
    let $tbrowEven = $(this.elementRef.nativeElement).find(".tbrow:even");
    console.log(".tbrow:even length => ",$tbrowEven.length);
    $tbrowEven.addClass("tbrow-even");
  }

在使用自己建立的樹狀結構變數treedata的狀況下,

可以成功顯示樹狀表格且換行變色。

實際串接API

使用http.get實際串接api後,

  ngOnInit() {
    let url = "http://beta.json-generator.com/api/json/get/NJAMxaRNz";
    this.http
      .get(url)
      .map((res:Response) => res.json())
      .subscribe((res) => {
        this.treedata = res;
        console.log("Receive Treedata !!!!!")
      });
  }

發現表格不會變色了,而且印出.tbrow:even的length居然是0

解決問題

在不斷的測試之下,我發現這個問題出在我用錯生命週期方法了

jQuery變色語法,應該要下在ngAfterViewChecked這個生命週期

印出所有生命週期如下圖,並觀察

ngOnInit雖然是我們串接連接遠端API的地方

但是Component的ngAfterContentInit及ngAfterViewInit

會早於真正取得資料的時間點,且這二個Life Cycle Hook只會執行一次

ngAfterContentChecked及ngAfterViewChecked,會在偵測到資料或View變動時觸發。

這個範例中,ngAfterContentChecked,不是我要用jQuery做表格換行變色的地方,

因為它是偵測Content Projection更新(這邊我們沒有使用ng-content)

所以ngAfterViewChecked才是正解!!!

現在來把程式碼換個地方

  ngAfterViewInit() {
	console.log("ngAfterViewInit");
	let $tbrowEven = $(this.elementRef.nativeElement).find(".tbrow:even");
	console.log(".tbrow:even length => ",$tbrowEven.length);
	// 把換行變色語法換到ngAfterViewChecked之下
  }
  
  ngAfterViewChecked() {
	console.log("ngAfterViewChecked");
	let $tbrowEven = $(this.elementRef.nativeElement).find(".tbrow:even");
	console.log(".tbrow:even length => ",$tbrowEven.length);
	$tbrowEven.addClass("tbrow-even");
  }

重新發現可以正常運作了

在開發Angular2的元件時,最好先了解Component Life Cycle

接下來的學習筆記,決定要來研讀官網的Component Life Cycle文件。

提供今天的Github專案進度檔案


上一篇
Angular2 實戰篇(七)
下一篇
Lifecycle Hooks 學習筆記 (一)
系列文
Angular2學習筆記19
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

1
KevinYang
iT邦新手 5 級 ‧ 2016-12-30 12:21:31

ㄎㄎ,我又來了,每天一留言
https://angular.io/docs/ts/latest/api/common/index/NgFor-directive.html
https://angular.io/docs/ts/latest/api/common/index/NgClass-directive.html

ngFor本身有提供odd, even的參數可以使用, 再搭配ngClass的寫法, 應該就可以省略Jquery那段

拉拉醬 iT邦新手 5 級 ‧ 2016-12-30 12:47:45 檢舉

哦哦,我可以回應了!
這個例子是把所有的樹每個節點的資料用表格的方式呈現
然後奇偶列要換行變色,
如果用ngFor就只能是當下區塊的奇偶列變色。
我目前想到的是等所有的DOM產生完
才用jQuery找到偶數的DOM做換色
不知還有沒有更好的做法,如果有的話可以一起討論一下!

KevinYang iT邦新手 5 級 ‧ 2016-12-30 15:37:38 檢舉

這個寫法呢? 跟你的做法類似,但不利用JQuery, 然後另外再建立一個tree-row的component處理.

https://gist.github.com/chgc/d441384ae38fb34b8e8af59d56d2c44f

拉拉醬 iT邦新手 5 級 ‧ 2016-12-30 16:26:18 檢舉

哦哦,你改用了原生的DOM選擇器querySelectorAll
效率會比jQuery的好!
如果是這樣的話,的確不需要特別把jQuery加進專案裡
總是會不知不覺得想用jQuery一下XDDD

我要留言

立即登入留言